/*****************************************************************************
 * Copyright (C) 2008 EnterpriseDB Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, see http://www.gnu.org/licenses or write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 *
 * You can contact EnterpriseDB, Inc. via its website at
 * http://www.enterprisedb.com
 *
 ****************************************************************************/
/*
 * SysIndex.java
 *
 *  
 */

package com.edb.gridsql.metadata;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.sql.*;

import com.edb.gridsql.exception.ErrorMessageRepository;
import com.edb.gridsql.exception.XDBServerException;

/**
 * class SysIndex caches data from xsysindexes (one record)
 * 
 * 
 */

public class SysIndex {
    public static final String ROWID_INDEXNAME = "IDX_XROWID";

    public SysTable sysTable; // index part of this table

    public int idxid = -1; // index id

    public String idxname; // index name

    public int tableid; // index create on table

    public int keycnt; // number of fields in the index

    private List<SysIndexKey> indexKeys; // Vector of columns in the index
                                            // key

    // represensented by SysIndexKey
    private List<SysColumn> sysColumnList; // SysColumn objects that make up
                                            // index

    public char idxtype; // type of Index - 'U'nique, 'P'rimary, 'R'eference

    // no more in physical schema - but lets keep it here
    // this is setup from xsysconstraints info.

    public int issyscreated; // is generated by system?

    public boolean is_constrained; // indicates if this participates in a
                                    // constraint ?

    public int estRowsPerPage = 0;

    public boolean isDistributed = false;

    // private SysUser owner;

    public int tablespaceID = -1;

    public String usingtype;

    public String wherepred;

    private int indexLength;

    // Constructor
    public SysIndex(SysTable aSysTable) {
        sysTable = aSysTable;
    }

    /**
     * Reads the index keys info for this index Also checks if this is part of
     * some constraint
     * 
     * Pre-Condition The indexId must be set correctly for this to work. Updates
     * the info in this index.
     * 
     * Throws an error if idxid does not exist
     */
    public void readIndexKeysInfo() throws Exception {
        if (idxid == -1) {
            // programmer error
            String errorMessage = ErrorMessageRepository.SYSINDEX_CORRUPT
                    + " ( " + idxid + " ) ";
            throw new XDBServerException(errorMessage, 0,
                    ErrorMessageRepository.SYSINDEX_CORRUPT_CODE);
        }

        try {

            // ----------------------------------------------------------
            // get indexkeys info
            ResultSet keysRS = MetaData.getMetaData().executeQuery(
                    "SELECT * FROM xsysindexkeys WHERE idxid = " + idxid
                            + " ORDER BY idxkeyseq");

            indexKeys = new ArrayList<SysIndexKey>();
            sysColumnList = new ArrayList<SysColumn>();

            int keys = 0;
            indexLength = 4; // assume 4 bytes to point to data page.

            while (keysRS.next()) {
                SysIndexKey aKey = new SysIndexKey();
                aKey.idxkeyid = keysRS.getInt("idxkeyid");
                aKey.idxid = keysRS.getInt("idxid");
                aKey.idxkeyseq = keysRS.getInt("idxkeyseq");
                aKey.idxascdesc = keysRS.getInt("idxascdesc");
                aKey.colid = keysRS.getInt("colid");
                aKey.coloperator = keysRS.getString("coloperator");

                // Also associate SysColumn object
                aKey.sysColumn = sysTable.getSysColumn(aKey.colid);

                keys++;
                indexKeys.add(aKey);

                // update sysColumnList
                sysColumnList.add(aKey.sysColumn);

                // Also update column info, noting index usage
                aKey.sysColumn.addIndexUsage(this, keys);
                indexLength += aKey.sysColumn.getColumnLength();
            }

            // Hmm - if no index keys are defined
            // BOMB out !
            if (keys == 0) {
                throw new SQLException("No index keys defined for " + idxname);
            }

            // set the number of keys correctly
            keycnt = keys;

            // Set the number of rows per index page
            estRowsPerPage = SysTable.PAGE_SIZE / indexLength;

        } catch (SQLException se) {
            String errorMessage = ErrorMessageRepository.SYSINDEX_READ_FAILURE
                    + " : " + idxname;
            throw new XDBServerException(errorMessage, 0,
                    ErrorMessageRepository.SYSINDEX_READ_FAILURE_CODE);
        }
    }

    /**
     * returns the vector of index keys
     */
    public List<SysIndexKey> getIndexKeys() {
        return indexKeys;
    }

    /*
     * Get the columns involved
     */
    public List<SysColumn> getKeyColumns() {
        return sysColumnList;
    }

    public int getIndexLength() {
        return indexLength;
    }

    @Override
    public String toString() {
        String result = "";
        switch (idxtype) {
        case 'P':
            result = "primary key ";
            break;
        case 'U':
            result = "unique index ";
            break;
        default:
            result = "index ";
        }
        if (idxname != null) {
            result += idxname + " ";
        }
        if (sysTable != null) {
            result += "on " + sysTable.getTableName() + " ";
            if (sysColumnList != null) {
                result += "(";
                for (Iterator<SysColumn> it = sysColumnList.iterator(); it
                        .hasNext();) {
                    SysColumn column = it.next();
                    result += column.getColName() + ", ";
                }
                result = result.substring(0, result.length() - 2) + ")";
            }
        }

        return result;
    }
}
